/*
package com.smart.tool.http;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;

*/
/**
 * @Author xiaoqiang
 * @Version HttpClientUtils.java, v 0.1 2025年05月18日 15:41 xiaoqiang
 * @Description: TODO
 *//*

public class HttpClientUtils {

    private static final Logger LOG = LoggerFactory.getLogger(HttpClientUtils.class);

    private static final PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager();
    private static final RequestConfig requestConfig;

    private static final HttpClientBuilder httpClientBuilder;
    private static final CloseableHttpClient httpClient;

    private static final IdleConnectionClearThread clearThread;

    private static final HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
        @Override
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
            if (executionCount >= 10) {
                // Do not retry if over max retry count
                return false;
            }
            if (exception instanceof NoHttpResponseException     //NoHttpResponseException 重试
                    || exception instanceof ConnectTimeoutException //连接超时重试
            ) {
                return true;
            }
            // otherwise do not retry
            return false;
        }
    };
    private static final ConnectionKeepAliveStrategy connectionKeepAliveStrategy = new ConnectionKeepAliveStrategy() {
        @Override
        public long getKeepAliveDuration(HttpResponse httpResponse, HttpContext httpContext) {
            return 20 * 1000;
        }
    };

    private HttpClientUtils() {
    }

    static {
        httpClientBuilder = HttpClientBuilder.create();
        connMgr.setMaxTotal(512);
        connMgr.setDefaultMaxPerRoute(100);
        RequestConfig.Builder configBuilder = RequestConfig.custom();
        configBuilder.setConnectTimeout(100000);
        configBuilder.setSocketTimeout(400000);

        configBuilder.setConnectionRequestTimeout(7000);
        configBuilder.setStaleConnectionCheckEnabled(true);
        requestConfig = configBuilder.build();
        httpClient = httpClientBuilder.setConnectionManager(connMgr)
                .setDefaultRequestConfig(requestConfig)
                .setKeepAliveStrategy(connectionKeepAliveStrategy)
                .setRetryHandler(retryHandler).build();
        clearThread = new IdleConnectionClearThread(connMgr);
        clearThread.start();
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                clearThread.shutdown();
            }
        }));
    }

    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslsf = null;

        try {
            SSLContext sslContext = (new SSLContextBuilder()).loadTrustMaterial((KeyStore) null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
                @Override
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }

                @Override
                public void verify(String host, SSLSocket ssl) throws IOException {
                }

                @Override
                public void verify(String host, X509Certificate cert) throws SSLException {
                }

                @Override
                public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
                }
            });
        } catch (Exception ex) {
            LOG.error("createSSLConnSocketFactory ERROR :{}", ex.getMessage(), ex);
        }

        return sslsf;
    }

    public static String doPostPay(String url, Object json, String authorization) throws Exception {
        String result = null;
        if (StringUtils.isEmpty(url)) {
            LOG.info("warn:doPostByJson url is null or '' ");
            return result;
        }
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        InputStream instream = null;

        try {
            StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");
            httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Authorization", authorization);
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json");
            httpPost.setEntity(stringEntity);
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            LOG.info("doPost statusCode:{}", statusCode);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                instream = entity.getContent();
                result = IOUtils.toString(instream, "UTF-8");
            }
        } catch (IOException ex) {
            LOG.error("doPost BY JSON ERROR :{}", ex.getMessage(), ex);
        } finally {
            IOUtils.closeQuietly(instream);
            IOUtils.closeQuietly(response);
            httpPost.releaseConnection();
        }

        return result;
    }

    public static String doPostPayUpgraded(String url, Object json, String authorization) throws Exception {
        String result = null;
        if (StringUtils.isEmpty(url)) {
            LOG.info("新支付接口url不能为空！");
            return result;
        }
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        InputStream instream = null;

        try {
            StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
            httpPost.setHeader("Authorization", authorization);
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json");
            httpPost.setEntity(stringEntity);
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            LOG.info("新支付请求状态 statusCode:{}", statusCode);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                instream = entity.getContent();
                result = IOUtils.toString(instream, "UTF-8");
            }
        } catch (Exception ex) {
            LOG.error("新支付接口发送异常:{}", ex.getMessage(), ex);
        } finally {
            IOUtils.closeQuietly(instream);
            IOUtils.closeQuietly(response);
            httpPost.releaseConnection();
        }

        return result;
    }


    public static <R> R doGet(String url, Function<InputStream, R> function) throws Exception {
        return doGet(url, new HashMap<>(), null, function);
    }

    public static <R> R doGet(String url, Map<String, String> uriParams,
                              Consumer<HttpGet> httpGetConsumer, Function<InputStream, R>
                                      function) throws Exception {
        R result = null;
        if (StringUtils.isEmpty(url)) {
            LOG.info("warn:doGet url is null or '' ");
            return result;
        }
        URIBuilder URIBuilder = generateURIBuilder(url, uriParams);
        CloseableHttpResponse response = null;
        InputStream instream = null;
        URI uri = URIBuilder.build();
        HttpGet httpGet = new HttpGet(uri);
        try {
            if (httpGetConsumer != null) {
                httpGetConsumer.accept(httpGet);
            }
            response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            LOG.info("doGet statusCode:{}", statusCode);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                instream = entity.getContent();
                result = function.apply(instream);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            LOG.error("doGet URISyntaxException :{}", ex.getMessage(), ex);
            throw ex;
        } finally {
            IOUtils.closeQuietly(instream);
            IOUtils.closeQuietly(response);
            httpGet.releaseConnection();
        }
        return result;
    }

    private static URIBuilder generateURIBuilder(String url, Map<String, String> params) throws URISyntaxException {
        URIBuilder URIBuilder = new URIBuilder(url);
        if (!CollectionUtils.isEmpty(params)) {
            List<NameValuePair> pairList = new ArrayList(params.size());
            Iterator paramIter = params.entrySet().iterator();

            while (paramIter.hasNext()) {
                Map.Entry entry = (Map.Entry) paramIter.next();
                NameValuePair pair = new BasicNameValuePair((String) entry.getKey(), entry.getValue().toString());
                pairList.add(pair);
            }
            URIBuilder.addParameters(pairList);
        }
        return URIBuilder;
    }


    public static String doPost(String apiUrl, Function<InputStream, String> function) throws Exception {
        return doPost(apiUrl, new HashMap<String, String>(), new HashMap<String, String>(), function);
    }

    public static <R> R doPost(String apiUrl, Map<String, String> params,
                               Map<String, String> headers,
                               Function<InputStream, R> function) throws Exception {
        R result = null;
        if (StringUtils.isEmpty(apiUrl)) {
            LOG.info("warn:doPost url is null or '' ");
            return result;
        }
        HttpPost httpPost = new HttpPost(apiUrl);
        CloseableHttpResponse response = null;
        InputStream instream = null;
        try {
            String param = generateURLParams(params, httpPost);
            LOG.info("http请求地址:" + apiUrl + "?" + param);
            //CloseableHttpClient httpClient = httpClientBuilder.build();
            if (!CollectionUtils.isEmpty(headers)) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    httpPost.addHeader(entry.getKey(), entry.getValue());
                }
            }
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            LOG.info("doPost statusCode:{}", statusCode);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                instream = entity.getContent();
                return function.apply(instream);
            }
        } catch (Exception ex) {
            LOG.error("doPost  ERROR :{}", ex.getMessage(), ex);
            throw new Exception(ex);
        } finally {
            IOUtils.closeQuietly(instream);
            IOUtils.closeQuietly(response);
            httpPost.releaseConnection();
        }
        return result;
    }

    public static String generateURLParams(Map<String, String> params, HttpPost httpPost) {
        String param = "";
        if (!CollectionUtils.isEmpty(params)) {
            List<NameValuePair> pairList = new ArrayList(params.size());
            Iterator temParam = params.entrySet().iterator();
            while (temParam.hasNext()) {
                Map.Entry entry = (Map.Entry) temParam.next();
                NameValuePair pair = new BasicNameValuePair((String) entry.getKey(), entry.getValue().toString());
                pairList.add(pair);
                if (param.equals("")) {
                    param = (String) entry.getKey() + "=" + entry.getValue();
                } else {
                    param = param + "&" + (String) entry.getKey() + "=" + entry.getValue();
                }
            }
            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));
        }
        return param;
    }

    */
/**
     * @param url
     * @param httpPostConsumer 处理参数
     *                         eg:StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");
     *                         httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
     *                         httpPost.setHeader("Accept", "application/json");
     *                         stringEntity.setContentEncoding("UTF-8");
     *                         stringEntity.setContentType("application/json");
     *                         httpPost.setEntity(stringEntity);
     * @param function         结果处理方法 eg: result = IOUtils.toString(instream, "UTF-8");
     * @param <R>              返回值类型
     * @return
     * @throws Exception
     *//*

    public static <R> R doPost(String url,
                               Consumer<HttpPost> httpPostConsumer,
                               Function<InputStream, R> function) {
        R result = null;
        if (StringUtils.isEmpty(url)) {
            LOG.info("warn:doPostByJson url is null or '' ");
            return result;
        }
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        InputStream instream = null;
        try {
            if (httpPostConsumer != null) {
                httpPostConsumer.accept(httpPost);
            }
            response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            LOG.info("doPost statusCode:{}", statusCode);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                instream = entity.getContent();
                result = function.apply(instream);
            }
        } catch (Exception ex) {
            LOG.error("doPost BY JSON ERROR :{},url:{},data:{}", ex.getMessage(), url, ex);
        } finally {
            IOUtils.closeQuietly(instream);
            IOUtils.closeQuietly(response);
            httpPost.releaseConnection();
        }
        return result;
    }

    public static <R> R doPostSSL(String apiUrl,
                                  Consumer<HttpPost> httpPostConsumer, Function<HttpResponse, R> function) throws Exception {
        R result = null;
        if (StringUtils.isEmpty(apiUrl)) {
            LOG.info("warn:doPostSSL url is null or '' ");
            return result;
        }
        CloseableHttpClient httpClient = httpClientBuilder.setSSLSocketFactory(createSSLConnSocketFactory()).build();
        HttpPost httpPost = new HttpPost(apiUrl);
        CloseableHttpResponse response = null;
        InputStream instream = null;
        try {
            if (httpPostConsumer != null) {
                httpPostConsumer.accept(httpPost);
            }
            response = httpClient.execute(httpPost);
            result = function.apply(response);
        } catch (Exception ex) {
            LOG.error("doPostSSL ERROR :{}", ex.getMessage(), ex);
        } finally {
            IOUtils.closeQuietly(instream);
            IOUtils.closeQuietly(response);
            LOG.info("close  instream response httpClient  connection succ");
        }
        return result;
    }

    */
/**
     * 文件上传，设置post 头
     *
     * @param fileInputStream
     * @param fileName
     * @param boundary
     * @param httpPost
     *//*

    */
/*public static void setHttpFileHeader(InputStream fileInputStream, String fileName, String boundary, HttpPost httpPost) {
        httpPost.setHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.setCharset(Charset.forName("UTF-8"));
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        builder.setBoundary(boundary);
        InputStreamBody inputStreamBody = new InputStreamBody(fileInputStream, fileName);
        builder.addPart("file", inputStreamBody);
        builder.addTextBody("filename", fileName, ContentType.create("text/plain", Consts.UTF_8));
        HttpEntity entity = builder.build();
        httpPost.setEntity(entity);
    }*//*

}

class IdleConnectionClearThread extends Thread {

    private final HttpClientConnectionManager connMgr;
    private volatile boolean exitFlag = false;

    public IdleConnectionClearThread(HttpClientConnectionManager connMgr) {
        this.connMgr = connMgr;
        setDaemon(true);
    }

    @Override
    public void run() {
        while (!this.exitFlag) {
            synchronized (this) {
                try {
                    this.wait(800);
                } catch (InterruptedException e) {

                }
            }
            // 关闭失效的连接
            connMgr.closeExpiredConnections();
            // 可选的, 关闭30秒内不活动的连接
            connMgr.closeIdleConnections(10, TimeUnit.SECONDS);
        }
    }

    public void shutdown() {
        this.exitFlag = true;
        synchronized (this) {
            notify();
        }
    }
}
*/
